<!DOCTYPE html>
<html lang="zh">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      body,
      html {
        width: 100%;
        height: 100%;
        overflow: hidden;
      }
    </style>
  </head>
  <body>
    <script type="module">
      import * as THREE from "three";
      import { OrbitControls } from "./node_modules/three/examples/jsm/controls/OrbitControls";
      import {
        scene,
        camera,
        renderer,
        loadFbx,
      } from "./person-roma/src/universal";
      import { ground, blocks } from "./person-roma/src//building";
      import ModelAnimation from "./person-roma/src/animation";

      //设置场景背景颜色
      scene.background = new THREE.Color(0xc9d6e7);

      // 设置相机
      camera.position.set(0, 0, 8); //设置相机位置
      camera.lookAt(0, 0, 0);

      //添加平面
      scene.add(ground);
      //添加建筑
      scene.add(...blocks);

      //加载模型
      let modelAnimation;
      let player;
      const loadModel = async () => {
        const object = await loadFbx("./model/ninja/ninja.fbx");
        player = object;
        object.scale.set(0.02, 0.02, 0.02); //对模型进行缩放
        object.traverse((child) => {
          if (child.isMesh) {
            child.castShadow = true; //支持投影
          }
        });
        scene.add(object);
        modelAnimation = new ModelAnimation(object);
        modelAnimation.start("Idle");
      };
      loadModel();

      // 键盘事件
      const keyPressed = {};
      let isJump = false; //跳跃
      let isDance = false;
      window.addEventListener("keydown", (event) => {
        const keycode = event.code.toLocaleLowerCase();
        //跳跃
        if (keycode === "space" && !isJump) {
          isJump = true;
          modelAnimation.updateAction("jump");
        }
        //跳舞
        if (keycode === "keyj" && !isDance) {
          isDance = true;
          modelAnimation.updateAction("flair");
        }
        //停止跳舞
        if (keycode === "k") {
          isDance = false;
        }
        keyPressed[keycode] = true;
      });
      window.addEventListener("keyup", (event) => {
        const keycode = event.code.toLocaleLowerCase();
        if (keycode === "space" && isJump) {
          setTimeout(() => {
            isJump = false;
          }, modelAnimation.getAnimationDuration("jump") * 800);
        }
        keyPressed[keycode] = false;
      });

      //更新人物朝向
      const updateLookAt = () => {
        const cameraDirection = new THREE.Vector3(); //相机朝向
        camera.getWorldDirection(cameraDirection);
        const lookAtPosition = new THREE.Vector3(); //人物朝向
        //声明一个速度向量
        const velocity = new THREE.Vector3(0, 0, 0.06);
        const originalLength = velocity.length(); //原始速度
        if (keyPressed["keyw"]) {
          //设置人物朝向与相机保持一致
          lookAtPosition.set(
            player.position.x + cameraDirection.x,
            player.position.y,
            player.position.z + cameraDirection.z
          );
          player.lookAt(lookAtPosition);
          //向前运动
          cameraDirection.y = 0;
          cameraDirection.normalize(); //归一化
          cameraDirection.setLength(originalLength);
          player.position.add(cameraDirection); //相加
        } else if (keyPressed["keys"]) {
          //设置人物朝向与相机朝向相反
          lookAtPosition.set(
            player.position.x - cameraDirection.x,
            player.position.y,
            player.position.z - cameraDirection.z
          );
          player.lookAt(lookAtPosition);
          //向后运动
          cameraDirection.y = 0;
          cameraDirection.normalize(); //归一化
          cameraDirection.setLength(originalLength);
          player.position.sub(cameraDirection); //相减
        } else if (keyPressed["keya"]) {
          const leftDirection = new THREE.Vector3(
            -cameraDirection.z,
            0,
            cameraDirection.x
          );
          lookAtPosition.set(
            player.position.x - leftDirection.x,
            player.position.y,
            player.position.z - leftDirection.z
          );
          player.lookAt(lookAtPosition);
          //向左运动
          leftDirection.setLength(originalLength);
          player.position.add(leftDirection.negate());
        } else if (keyPressed["keyd"]) {
          const rightDirection = new THREE.Vector3(
            cameraDirection.z,
            0,
            -cameraDirection.x
          );
          lookAtPosition.set(
            player.position.x - rightDirection.x,
            player.position.y,
            player.position.z - rightDirection.z
          );
          player.lookAt(lookAtPosition);
          //向右运动
          rightDirection.setLength(originalLength);
          player.position.add(rightDirection.negate());
        }
      };

      // 更新人物动作
      const updateAnimation = () => {
        if (isJump) return;
        if (isDance) return;
        if (
          (keyPressed["shiftleft"] && keyPressed["keyw"]) ||
          (keyPressed["shiftleft"] && keyPressed["keya"]) ||
          (keyPressed["shiftleft"] && keyPressed["keys"]) ||
          (keyPressed["shiftleft"] && keyPressed["keyd"])
        ) {
          //切换成奔跑动作
          modelAnimation.updateAction("run");
        } else if (
          keyPressed["keyw"] ||
          keyPressed["keya"] ||
          keyPressed["keys"] ||
          keyPressed["keyd"]
        ) {
          //切换成走路的动作
          modelAnimation.updateAction("walk");
        } else if (keyPressed["space"]) {
          //切换成跳跃动作
          modelAnimation.updateAction("jump");
        } else {
          //切换成站立状态
          modelAnimation.updateAction("Idle");
        }
      };

      new OrbitControls(camera, renderer.domElement);

      // 动画
      const clock = new THREE.Clock();
      const animate = () => {
        const dt = clock.getDelta();
        if (modelAnimation) {
          modelAnimation.update(dt);
          updateAnimation();
        }
        updateLookAt();
        renderer.render(scene, camera);
        window.requestAnimationFrame(animate);
      };

      window.requestAnimationFrame(animate);
    </script>
  </body>
</html>
